package fasdk

import (
	"encoding/hex"
	"encoding/pem"
	"fmt"
	"gitee.com/bupt-zkjc/fabric-sdk-go/third_party/github.com/hyperledger/fabric/core/ledger/util"

	utils "gitee.com/bupt-zkjc/fabric/protoutil"
	//cutil "gitee.com/bupt-zkjc/fabric/core/ledger/util"
	"github.com/hyperledger/fabric-protos-go/common"
	cm "github.com/hyperledger/fabric-protos-go/common"

	"time"
)

type FabricBlock struct {
	Number uint64 `json:"Number"`
	CurrentBlockHash string `json:"CurrentBlockHash"`
	PreviousBlockHash string `json:"PreviousBlockHash"`
	Transactions []BlockTransaction `json:"Transactions"`
}

type BlockTransaction struct {
	No int64 `json:"No"`
	Status string `json:"Status"`
	MspId string `json:"MspId"`   //交易发起者MSPID
	Payload []string `json:"Payload"`  //输入参数
	TxId string `json:"TxId"`
	Channel string `json:"Channel"`
	TimeStamp string `json:"Timestamp"`
}

type FabricTransaction struct {
	No int64 `json:"No"`
	Status string `json:"Status"`
	ChaincodeID string  `json:"ChaincodeID"` //交易调用链码ID
	ChaincodeVersion string  `json:"ChaincodeVersion"`  //交易调用链码版本
	MspId string `json:"MspId"`   //交易发起者MSPID
	Payload []string `json:"Payload"`  //输入参数
	TxId string `json:"TxId"`
	Channel string `json:"Channel"`
	TimeStamp string `json:"Timestamp"`
}

func blockParse(block *cm.Block ) *common.Block{
	if block == nil {
		return nil
	}
	cmBlock := new(common.Block)
	cmBlock.Data = &common.BlockData{
		Data:block.Data.Data,
	}
	cmBlock.Header= &common.BlockHeader{
		Number: block.Header.Number,
		PreviousHash: block.Header.PreviousHash,
		DataHash: block.Header.DataHash,
	}
	cmBlock.Metadata =&common.BlockMetadata{
		Metadata: block.Metadata.Metadata,
	}
	return cmBlock
}

func parseBlock(block *common.Block) (*FabricBlock,error) {
	if block == nil {
		return nil,nil
	}

	var err error
	faBlock := new(FabricBlock)
	trans := make([]BlockTransaction,0)
	// Handle header
	faBlock.Number = block.GetHeader().Number
	faBlock.CurrentBlockHash = hex.EncodeToString(utils.Hash(block.GetHeader()))

	faBlock.PreviousBlockHash = hex.EncodeToString(block.GetHeader().PreviousHash)
	// Handle transaction
	var tranNo int64 = -1
	txsFilter := util.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
	if len(txsFilter) == 0 {
		txsFilter = util.NewTxValidationFlags(len(block.Data.Data))
		block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txsFilter
	}

	for _, envBytes := range block.Data.Data {
		tran := BlockTransaction{}
		tranNo++
		tran.No = tranNo
		if txsFilter.IsInvalid(int(tranNo)) {
			tran.Status = "INVALID"
			continue
		} else {
			tran.Status = "VALID"
		}

		var env *common.Envelope
		if env, err = utils.GetEnvelopeFromBlock(envBytes); err != nil {
			return nil,err
		}

		var payload *common.Payload
		if payload, err = utils.GetPayload(env); err != nil {
			return nil,err
		}

		var chdr *common.ChannelHeader
		chdr, err = utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
		if  err != nil {
			return nil,err
		}
		signHeader, err := utils.UnmarshalSignatureHeader(payload.Header.SignatureHeader)
		if err != nil {
			return nil, err
		}
		identity, err := utils.UnmarshalSerializedIdentity(signHeader.GetCreator())
		if err != nil {
			return nil, err
		}
		tran.TxId = chdr.TxId
		tran.Channel = chdr.ChannelId
		tran.TimeStamp = time.Unix(chdr.Timestamp.Seconds, 0).Format("2006/01/02 15:04:05")
		tran.MspId = identity.GetMspid()

		trans = append(trans,tran)
	}
	faBlock.Transactions = trans
	return faBlock,nil
}

func transactionParse(payloadRaw []byte) (*FabricTransaction, error) {
	result := &FabricTransaction{}
	//解析成payload
	payload, err := utils.UnmarshalPayload(payloadRaw)
	if err != nil {
		return nil, err
	}
	//解析成ChannelHeader（包含通道ID、交易ID及交易创建时间等)
	channelHeader, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader)
	if err != nil {
		return nil, err
	}
	//解析成SignatureHeader（包含创建者和nonce)
	signHeader, err := utils.UnmarshalSignatureHeader(payload.Header.SignatureHeader)
	if err != nil {
		return nil, err
	}
	//解析成SerializedIdentity（包含证书和MSPID）
	identity, err := utils.UnmarshalSerializedIdentity(signHeader.GetCreator())
	if err != nil {
		return nil, err
	}

	block, _ := pem.Decode(identity.GetIdBytes())
	if block == nil {
		return nil, fmt.Errorf("identity could not be decoded from credential")
	}

	//解析成transaction
	tx, err := utils.UnmarshalTransaction(payload.Data)
	if err != nil {
		return nil, err
	}
	//进一步从transaction中解析成ChaincodeActionPayload
	chaincodeActionPayload, err := utils.UnmarshalChaincodeActionPayload(tx.Actions[0].Payload)
	if err != nil {
		return nil, err
	}
	//进一步解析成proposalPayload
	proposalPayload, err := utils.UnmarshalChaincodeProposalPayload(chaincodeActionPayload.ChaincodeProposalPayload)
	if err != nil {
		return nil, err
	}
	//得到交易调用的链码信息
	chaincodeInvocationSpec, err := utils.UnmarshalChaincodeInvocationSpec(proposalPayload.Input)
	if err != nil {
		return nil, err
	}
	//得到调用的链码的ID，版本）
	result.ChaincodeID = chaincodeInvocationSpec.ChaincodeSpec.ChaincodeId.Name
	result.ChaincodeVersion = chaincodeInvocationSpec.ChaincodeSpec.ChaincodeId.Version
	//得到输入参数
	var args []string
	for _, v := range chaincodeInvocationSpec.ChaincodeSpec.Input.Args {
		args = append(args, string(v))
	}
	result.Payload = args
	result.TxId = channelHeader.GetTxId()
	result.MspId = identity.GetMspid()
	result.TimeStamp = time.Unix(channelHeader.Timestamp.Seconds,0 ).Format("2006/01/02 15:04:05")
	return result, nil
}

